package com.stylefeng.guns.modular.system.controller;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.enums.SqlLike;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.stylefeng.guns.core.base.controller.BaseController;
import com.stylefeng.guns.core.cache.CacheKit;
import com.stylefeng.guns.core.common.Tools.CodeMsg;
import com.stylefeng.guns.core.common.Tools.Result;
import com.stylefeng.guns.core.common.annotion.BussinessLog;
import com.stylefeng.guns.core.common.constant.dictmap.FunctionDict;
import com.stylefeng.guns.core.common.constant.state.MenuStatus;
import com.stylefeng.guns.core.common.constant.state.SpType;
import com.stylefeng.guns.core.common.exception.BizExceptionEnum;
import com.stylefeng.guns.core.exception.GunsException;
import com.stylefeng.guns.core.log.LogObjectHolder;
import com.stylefeng.guns.core.node.List2ZTree;
import com.stylefeng.guns.core.node.ZTreeNode;
import com.stylefeng.guns.core.shiro.ShiroUser;
import com.stylefeng.guns.core.util.ToolUtil;
import com.stylefeng.guns.core.validater.Insert;
import com.stylefeng.guns.modular.system.model.Function;
import com.stylefeng.guns.modular.system.model.SysPrivilege;
import com.stylefeng.guns.modular.system.service.IFunctionService;
import com.stylefeng.guns.modular.system.service.ISysPrivilegeService;
import com.stylefeng.guns.modular.system.warpper.FunctionWarpper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.collections.FastArrayList;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.inject.Inject;
import javax.validation.Valid;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 菜单管理(成为智能)控制器
 *
 * @author 张亚林
 * @Date 2018-08-31 17:55:41
 */
@Controller
@RequestMapping(value = {"/gunsApi/auth/function"})
@Api(value="系统功能相关api",tags={"系统功能操作接口"})
public class FunctionController extends BaseController {

    private String PREFIX = "/system/function/";

    @Autowired
    private IFunctionService functionService;

    @Inject
    private ISysPrivilegeService privilegeService;

    /**
     * 跳转到菜单管理(成为智能)首页
     */
    @RequestMapping("")
    public String index() {
        return PREFIX + "function.html";
    }

    /**
     * 跳转到添加菜单管理(成为智能)
     */
    @RequestMapping("/function_add")
    public String functionAdd() {
        return PREFIX + "function_add.html";
    }


    /**
     * 获取菜单管理(成为智能)列表
     */
    @ApiOperation(value="获取功能项",notes="获取功能项",httpMethod ="GET")
    @GetMapping(value = "/list")
    @ResponseBody
    public Result list(@ApiParam(name = "menuName", value = "菜单名", required = false) @RequestParam(value="menuName",required = false) String menuName,
                       @ApiParam(name = "level", value = "菜单层级", required = false)  @RequestParam(value="level",required = false) Integer level,
                       @ApiParam(name = "flag", value = "是否过滤(0:不过滤菜单 1:过滤菜单)", required = false)  @RequestParam(value="flag",required = false) Integer flag) {
        Map<String, Object> conditionMap=new HashMap<>();
        if (StringUtils.isNotBlank(menuName))
            conditionMap.put("sf_name",menuName);
        if(ToolUtil.isNotEmpty(level))
            conditionMap.put("sf_level",level);
        if(ToolUtil.isNum(flag))
            conditionMap.put("sf_ismenu",flag);
        ShiroUser  user=this.getShiroUser();
        List<String> permissions=new FastArrayList();//权限集合
        if(user!=null){
            permissions=user.permissions;
        }
        
        List<Function>  menus = this.functionService.selectByMap(conditionMap);
        //排序  层级  排序字段
        Collections.sort(menus,Comparator.comparing(Function::getSfLevel).thenComparing(Function::getSfSort));
        List<Function> filter=new FastArrayList();
        // 超级管理员不做权限过滤
        if (!user.getRoleNames().contains("超级管理员")){
            List<String> perList=menus.parallelStream().map(Function::getSfUrl).collect(Collectors.toList());
            perList.retainAll(permissions);
            for(Function function:menus){
                here:
                for (String str:perList){
                if(StringUtils.equals(function.getSfUrl(), str)){
                    filter.add(function);
                    break here;
                }
            }
            }
            menus=filter;
        }
        
        List<Map<String, Object>> mList=new ArrayList<>();
        for (Object o:menus){
            Map map= BeanUtil.beanToMap(o);
            mList.add(map);
        }
        return Result.success(super.warpObject(new FunctionWarpper(mList)));
    }
    
    /**
     * 获取菜单管理(按钮)列表
     */
    @ApiOperation(value="获取菜单子项",notes="获取菜单子项",httpMethod ="GET")
    @GetMapping(value = "/sonList")
    @ResponseBody
    public Result sonList(@ApiParam(name = "funId", value = "菜单ID", required = true)  @RequestParam(value="funId",required = true) Integer funId) {
        Wrapper<Function> wrapper = new EntityWrapper<>();
        wrapper.eq("sf_pid",funId);
        List<Function> menus= this.functionService.selectList(wrapper);
         List<Map<String, Object>> mList=new ArrayList<>();
        //获取角色对应的功能
        List<Function> menus_f=new ArrayList<>();
        ShiroUser shiroUser=this.getShiroUser();
        if(shiroUser!=null){
            List<String> list_menu= shiroUser.getPermissions();
            for(Function f:menus){
            for(String of:list_menu){
                if(StringUtils.equals(f.getSfUrl(),of)){
                    menus_f.add(f);
                    break;
                }
            }
         }
        }
        for (Object o:menus_f){
            Map map= BeanUtil.beanToMap(o);
            mList.add(map);
        }
        return Result.success(super.warpObject(new FunctionWarpper(mList)));
    }
    
    /**
     * 新增菜单管理(成为智能)
     */
    @ApiOperation(value="添加功能项",notes="添加功能项",httpMethod ="POST")
    @PostMapping(value = "/add",produces="application/json",consumes = "application/json")
    @BussinessLog(value = "菜单新增")
    @ResponseBody
    public Result add(@Validated(value = Insert.class) @RequestBody @ApiParam(name="function",value="添加功能")  Function function, BindingResult result) {
        if (result.hasErrors()) {
            throw new GunsException(BizExceptionEnum.REQUEST_NULL);
        }
        //判断是否存在该编号
       ShiroUser shiroUser = this.getShiroUser();
        Function t=new Function();
        t.setSfCode(function.getSfCode());
        t.setSfName(function.getSfName());
        t = this.functionService.selectOne(new EntityWrapper<>(t));
        if(t!=null) {
            String existedMenuName = t.getSfName();
            if (ToolUtil.isNotEmpty(existedMenuName)) {
                throw new GunsException(BizExceptionEnum.EXISTED_THE_MENU);
            }
        }
        //设置父级菜单编号
        menuSetPcode(function);

        function.setSfState(MenuStatus.ENABLE.getCode());
        function.setCreateTime(new Date());
        function.setCreateBy(shiroUser.getAccount()+"|"+shiroUser.getName());
        this.functionService.insert(function);
        return Result.success();
    }

    /**
     * 根据请求的父级菜单编号设置pcode和层级
     */
    private void menuSetPcode(@Valid Function menu) {
        if (ToolUtil.isEmpty(menu.getSfPcode()) || menu.getSfPcode().equals("0")) {
            menu.setSfPcode("0");
            menu.setSfPcodes("[0],");
            menu.setSfLevel(1);
        } else {
            String code = menu.getSfPcode();
            Wrapper<Function> wrapper=new EntityWrapper<>();
            wrapper.eq("sf_code",code);
            Function pMenu = this.functionService.selectOne(wrapper);
            Integer pLevels = pMenu.getSfLevel();
            menu.setSfPcode(pMenu.getSfCode());

            //如果编号和父编号一致会导致无限递归
            if (menu.getSfCode().equals(menu.getSfPcode())) {
                throw new GunsException(BizExceptionEnum.MENU_PCODE_COINCIDENCE);
            }

            menu.setSfLevel(pLevels + 1);
            menu.setSfPcodes(pMenu.getSfPcodes() + "[" + pMenu.getSfCode() + "],");
            menu.setSfPid(pMenu.getSfId());
            menu.setSfPids(StringUtils.join(StringUtils.isNotBlank(pMenu.getSfPids())?pMenu.getSfPids():"") + "[" + pMenu.getSfId() + "],");
        }
    }

    /**
     * 获取角色功能列表
     */
    @ApiImplicitParam(name = "roleId", value = "角色ID", required = true, dataType = "String",paramType="query")
    @ApiOperation(value="获取角色功能列表",notes="获取角色功能列表",httpMethod ="GET")
    @GetMapping(value = "/menuTreeListByRoleId")
    @ResponseBody
    public Result menuTreeListByRoleId() {
        Result result=null;
        try {
            //判断是否存在该编号
             ShiroUser shiroUser =this.getShiroUser();
            String roleId=StringUtils.join(shiroUser.getRoleList().toArray(),",");

            SysPrivilege sysPrivilege=new SysPrivilege();
            sysPrivilege.setSpType(SpType.ROLE.getCode());
            sysPrivilege.setSpTypeId(roleId);
            List<SysPrivilege> list =this.privilegeService.selectListSysPrivilege(sysPrivilege);
            List menuIds=list.stream().sorted(Comparator.comparing(SysPrivilege::getSpFunctionId)).map(SysPrivilege::getSpFunctionId).collect(Collectors.toList());
            if (ToolUtil.isEmpty(menuIds)) {
                List<ZTreeNode> roleTreeList = this.functionService.menuTreeList();
                result=Result.success(List2ZTree.toTree01(roleTreeList));
            } else {
                List<ZTreeNode> roleTreeListByUserId = this.functionService.menuTreeListByMenuIds(menuIds);
                result=Result.success(List2ZTree.toTree02(roleTreeListByUserId));

            }
        }catch(Exception e){

            result=Result.error(CodeMsg.SERVER_EXCEPTION,e.getMessage());
        }

        return result;
    }


    /**
     * 删除菜单管理(成为智能)
     */
    @ApiOperation(value="删除功能项",notes="删除功能项",httpMethod ="GET")
    @GetMapping(value = "/delete")
    @BussinessLog(value = "删除菜单", key = "sfCode,sfName,sfUrl", dict = FunctionDict.class)
    @ResponseBody
    public Result delete(@ApiParam(name = "functionId",value="功能ID",required = true) @RequestParam(value = "functionId") Integer functionId) {
        if (ToolUtil.isEmpty(functionId)) {
            throw new GunsException(BizExceptionEnum.REQUEST_NULL);
        }
        if(functionId.equals(1)){//系统管理不能删除
            throw new GunsException(BizExceptionEnum.CANT_DELETE_SYSTEM);
        }
        Function f =this.functionService.selectById(functionId);
        //缓存菜单的名称
        LogObjectHolder.me().set(f.getSfName());

        Wrapper<Function> wrapper = new EntityWrapper<>();
        wrapper.like("sf_pcodes",f.getSfCode(), SqlLike.DEFAULT);
        
        //删除本尊
        this.functionService.deleteById(functionId);
        //删除子菜单
        this.functionService.delete(wrapper);
        return Result.success();
    }

    /**
     * 修改菜单管理(成为智能)
     */
    @ApiOperation(value="修改功能项",notes="修改功能项",httpMethod ="POST")
    @PostMapping(value = "/update",produces="application/json",consumes = "application/json")
    @BussinessLog(value = "修改菜单", key = "sfName,sfCode", dict = FunctionDict.class)
    @ResponseBody
    public Result update(@ApiParam(name = "function",value="功能ID",required = true) @Valid @RequestBody Function function,BindingResult result) {
        if (result.hasErrors()) {
            throw new GunsException(BizExceptionEnum.REQUEST_NULL);
        }
        ShiroUser shiroUser = this.getShiroUser();
        if(shiroUser!=null){
            function.setUpdateTime(new Date());
            function.setUpdateBy(shiroUser.getAccount()+"|"+shiroUser.getName());
        }
        if(new Integer(1).equals(function.getSfId())){
            throw new GunsException(BizExceptionEnum.CANT_FREEZE_ADMIN);
        }
        menuSetPcode(function);
        functionService.updateById(function);
        return Result.success();
    }

    /**
     * 菜单管理(成为智能)详情
     */
    @ApiOperation(value="菜单详情",notes="菜单详情",httpMethod ="GET")
    @GetMapping(value = "/detail/{functionId}")
    @ResponseBody
    public Result detail(@PathVariable("functionId") Integer functionId) {
         Function f= functionService.selectById(functionId);
        List<Map<String, Object>> mList=new ArrayList<>();
         if(ToolUtil.isNotEmpty(f)){
            Map map= BeanUtil.beanToMap(f);
            mList.add(map);
         }else{
             throw new GunsException(BizExceptionEnum.CANT_CHANGE_SYSTEM);
         }
        return Result.success(super.warpObject(new FunctionWarpper(mList)));
    }
    @Cacheable(value="local",key = "'userCw_'+#result.getId()")
    public  ShiroUser getShiroUser(){
        String token= getHttpServletRequest().getHeader("Authorization").substring(7);
        return CacheKit.get(CACHE_STRATEGY,token);
    }

}
